use serde::{Deserialize, Serialize};
use wither::{
    bson::{oid::ObjectId, DateTime},
    Model,
};

use super::{
    page::PageModel,
    user::{NormalUserModel, SimpleUserModel},
    Assets,
};

/// ## 社团活动位置
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum ClubActivityLocation {
    /// ## 在线活动
    Online {
        /// ## 活动的url (可选)
        url: Option<String>,
        /// ## 活动的预览图url (可选)
        preview: Option<String>,
    },
    /// ## 线下活动
    Offline {
        /// ## 线下地址
        address: String,
        /// ## 位置坐标
        position: Option<String>,
    },
}

impl Default for ClubActivityLocation {
    fn default() -> Self {
        Self::Online {
            url: None,
            preview: None,
        }
    }
}

/// ## 社团活动模型
#[derive(Debug, Clone, Serialize, Deserialize, Model)]
pub struct ClubActivityModel {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    /// 社团id
    pub club_id: ObjectId,
    /// 表单id(可选)，如果存在那么参加活动的时候就需要填表
    pub form_id: Option<ObjectId>,
    pub name: String,
    pub description: Option<String>,
    pub page: Option<PageModel>,
    pub location: ClubActivityLocation,
    /// 活动开始时间
    pub beginning_time: DateTime,
    /// 活动结束时间
    pub ended_time: Option<DateTime>,
    #[serde(default = "Default::default")]
    pub last_weak_heat: f64,
    #[serde(default = "Default::default")]
    pub heat: f64,
    #[serde(default = "Default::default")]
    pub watch_count: i64,
    /// 活动数据软删除
    pub valid: bool,
    /// 活动是否启用
    pub is_enabled: bool,
    pub created_at: DateTime,
    pub updated_at: DateTime,
}

impl_modifyed_for_model!(ClubActivityModel, updated_at);

impl Default for ClubActivityModel {
    fn default() -> Self {
        Self {
            id: None,
            club_id: ObjectId::new(),
            form_id: None,
            name: String::new(),
            description: None,
            page: None,
            location: Default::default(),
            beginning_time: DateTime::now(),
            ended_time: None,
            last_weak_heat: 0.0,
            heat: 0.0,
            watch_count: 0,
            valid: true,
            is_enabled: true,
            created_at: DateTime::now(),
            updated_at: DateTime::now(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
/// ## 社团活动对应的DTO
pub struct ClubActivityModelDTO {
    pub id: Option<String>,
    pub club_id: String,
    pub form_id: Option<String>,
    pub name: String,
    pub description: Option<String>,
    pub page: Option<PageModel>,
    pub location: ClubActivityLocation,
    pub beginning_time: chrono::DateTime<chrono::Utc>,
    pub ended_time: Option<chrono::DateTime<chrono::Utc>>,
    pub last_weak_heat: f64,
    pub heat: f64,
    pub watch_count: i64,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

impl From<ClubActivityModel> for ClubActivityModelDTO {
    fn from(m: ClubActivityModel) -> Self {
        Self {
            id: m.id.as_ref().map(ObjectId::to_string),
            club_id: m.club_id.to_string(),
            form_id: m.form_id.as_ref().map(ObjectId::to_string),
            name: m.name,
            description: m.description,
            page: m.page,
            location: m.location,
            beginning_time: m.beginning_time.to_chrono(),
            ended_time: m.ended_time.map(DateTime::to_chrono),
            last_weak_heat: m.last_weak_heat,
            heat: m.heat,
            watch_count: m.watch_count,
            created_at: m.created_at.to_chrono(),
            updated_at: m.updated_at.to_chrono(),
        }
    }
}

/// ## 报名参加社团活动的用户
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ClubActivityJoinedUser {
    pub id: ObjectId,
    pub nickname: String,
    pub avatar: Option<Assets>,
}
impl From<ClubActivityJoinedUser> for SimpleUserModel {
    fn from(v: ClubActivityJoinedUser) -> Self {
        Self {
            id: v.id,
            nickname: v.nickname,
            avatar: v.avatar,
        }
    }
}

impl From<NormalUserModel> for ClubActivityJoinedUser {
    fn from(m: NormalUserModel) -> Self {
        Self {
            id: m.id,
            nickname: m.nickname,
            avatar: m.avatar,
        }
    }
}

/// ## 报名参加社团活动的用户对应的DTO
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClubActivityJoinedUserDTO {
    pub id: String,
    pub nickanme: String,
    pub avatar: Option<Assets>,
}

impl From<ClubActivityJoinedUser> for ClubActivityJoinedUserDTO {
    fn from(c: ClubActivityJoinedUser) -> Self {
        Self {
            id: c.id.to_hex(),
            nickanme: c.nickname,
            avatar: c.avatar,
        }
    }
}

/// ## 社团活动参加记录
#[derive(Debug, Clone, Serialize, Deserialize, Model)]
pub struct ClubActivityJoinModel {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    /// 活动id
    pub activity_id: ObjectId,
    /// 如果参加活动需要提交表单那么这里就是表单id
    pub application_id: Option<ObjectId>,
    /// 参加的用户
    pub joined_user: ClubActivityJoinedUser,
    pub created_at: DateTime,
}

impl Default for ClubActivityJoinModel {
    fn default() -> Self {
        Self {
            id: None,
            activity_id: ObjectId::default(),
            application_id: None,
            joined_user: ClubActivityJoinedUser::default(),
            created_at: DateTime::now(),
        }
    }
}

/// ## 社团活动参加记录对应的DTO
#[derive(Clone, Serialize, Deserialize)]
pub struct ClubActivityJoinModelDTO {
    pub id: Option<String>,
    pub activity_id: String,
    pub joined_usser: ClubActivityJoinedUserDTO,
    pub created_at: chrono::DateTime<chrono::Utc>,
}

impl From<ClubActivityJoinModel> for ClubActivityJoinModelDTO {
    fn from(m: ClubActivityJoinModel) -> Self {
        Self {
            id: m.id.as_ref().map(ObjectId::to_string),
            activity_id: m.activity_id.to_string(),
            joined_usser: ClubActivityJoinedUserDTO::from(m.joined_user),
            created_at: m.created_at.to_chrono(),
        }
    }
}
